package com.pe.pgn.clubpgn.dao.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.sql.DataSource;

import org.apache.commons.lang.StringUtils;
import org.hibernate.Criteria;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

import com.pe.pgn.clubpgn.common.CLPConstantes;
import com.pe.pgn.clubpgn.dao.DevolucionProveedorDao;
import com.pe.pgn.clubpgn.dao.hibernate.GenericDaoHibernate;
import com.pe.pgn.clubpgn.domain.ClpbAlmacen;
import com.pe.pgn.clubpgn.domain.ClpbDocumentoMovArticulo;
import com.pe.pgn.clubpgn.domain.ClpdArticulo;
import com.pe.pgn.clubpgn.domain.ClpdDocumentoMovArticulo;
import com.pe.pgn.clubpgn.domain.ClpmStockAlmacenCatalogo;
import com.pe.pgn.clubpgn.domain.ClpmTransaccionArticulo;
import com.pe.pgn.clubpgn.domain.beans.BNArticulo;
import com.pe.pgn.clubpgn.webapp.util.CalendarUtil;

@Repository("devolucionProveedorDao")
public class DevolucionProveedorDaoImpl extends
GenericDaoHibernate<ClpbDocumentoMovArticulo, Long> implements
DevolucionProveedorDao {

	public DevolucionProveedorDaoImpl() {
		super(ClpbDocumentoMovArticulo.class);
	}

	private JdbcTemplate jdbcTemplate;

	@Autowired
	public void setDataSource(DataSource dataSource) {
		this.jdbcTemplate = new JdbcTemplate(dataSource);
	}

	@SuppressWarnings("unchecked")
	public List<ClpbDocumentoMovArticulo> busquedaDocumentoDevolucion(
			Long coAlmacen, String deProveedor, String fechaInicio,
			String fechaFin) {
		// Busqueda de documentos de devolucion al proveedor
		Criteria criteria = DetachedCriteria.forClass(ClpbDocumentoMovArticulo.class)
		.getExecutableCriteria(getSessionFactory().getCurrentSession());

		criteria.setMaxResults(CLPConstantes.MAXIMO_RESULTADO_INICIAL);
		if (StringUtils.isNotBlank(deProveedor))
			criteria.add(Restrictions.like("deProveedor", "%"+deProveedor + "%"));
		
		try {
			
			if(StringUtils.isNotBlank(fechaInicio) && StringUtils.isNotBlank(fechaFin))
				criteria.add(Restrictions.between("daFechaDocumento", CalendarUtil.stringToCalendar(CLPConstantes.DATE_PATTERN, fechaInicio), 
						CalendarUtil.stringToCalendar(CLPConstantes.DATE_PATTERN, fechaFin)));
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		
		if (coAlmacen>0)
			criteria.add(Restrictions.like("clpbAlmacen.id", coAlmacen));
		
		
		criteria.add(Restrictions.eq("stIndicadorTipoDocumento", CLPConstantes.ST_DOCUMENTO_DEVOLUCION_PROVEEDOR));
		criteria.add(Restrictions.eq("stDocumentoMovArticulo", Boolean.TRUE));
		criteria.addOrder(Order.desc("id"));
		
        return (List<ClpbDocumentoMovArticulo>) criteria.list();
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	public Map guardarDocumentoDevolucion(
			ClpbDocumentoMovArticulo documentoMovArticulo) {
		
		Map mapResult = new HashMap();
		
		try{

			List<BNArticulo> listDetalle = documentoMovArticulo.getArticulosDetalle();
			documentoMovArticulo.setCoUsuarioCreador(getUsuarioLogueado().getUsername());
			documentoMovArticulo.setDaFechaCreacion(Calendar.getInstance());
			documentoMovArticulo.setDaFechaDocumento(Calendar.getInstance());
			
			documentoMovArticulo.setStDocumentoMovArticulo(Boolean.TRUE);
			documentoMovArticulo.setStIndicadorTipoDocumento(CLPConstantes.
			ST_DOCUMENTO_DEVOLUCION_PROVEEDOR);
			
			getHibernateTemplate().saveOrUpdate(documentoMovArticulo);
			
			Map mapStockAlmCat = new HashMap();
			List<ClpdArticulo> listaArticulos = new ArrayList<ClpdArticulo>();
			List<ClpdDocumentoMovArticulo> listaDetalles = new ArrayList<ClpdDocumentoMovArticulo>();		
			List<ClpmTransaccionArticulo> listaTransacciones = new ArrayList<ClpmTransaccionArticulo>();		
	
			if(!listDetalle.isEmpty()){
				for (Iterator<BNArticulo> iter = listDetalle.iterator(); iter.hasNext();) {
					
					BNArticulo articulo = iter.next();
					String coCodigoArticulo = articulo.getCoCodigoArticulo();
					
					if (coCodigoArticulo != null){
						
						ClpdArticulo articuloActualizado = 
						obtenerDatosArticuloByCode(coCodigoArticulo);
						
						ClpdDocumentoMovArticulo documentoMov = new ClpdDocumentoMovArticulo();			
						documentoMov.setClpdArticulo(articuloActualizado);
						documentoMov.setClpbDocumento(documentoMovArticulo);
						documentoMov.setStDocumentoMovArticulo(Boolean.TRUE);
						documentoMov.setCoUsuarioCreador(getUsuarioLogueado().getUsername());
						documentoMov.setDaFechaCreacion(Calendar.getInstance());
						documentoMov.setVaCantidad(articulo.getVaCantidad());				
						
						//transacciones
						ClpmTransaccionArticulo transaccion = new ClpmTransaccionArticulo();
						transaccion.setClpdArticulo(articuloActualizado);
						transaccion.setClpbDocumentoMovArticulo(documentoMovArticulo);
						transaccion.setCoCodigoArticulo(coCodigoArticulo);
						transaccion.setStIndicadorTipoMovimiento(CLPConstantes.DEVOLUCION_DE_ARTICULO_A_PROVEEDOR);
						transaccion.setVaCantidad(documentoMov.getVaCantidad());
						transaccion.setClpbAlmacen(documentoMovArticulo.getClpbAlmacen());
						transaccion.setCoUsuarioCreador(getUsuarioLogueado().getUsername());
						transaccion.setDaFechaCreacion(Calendar.getInstance());				
						
						Long coAlmacen = documentoMovArticulo.getClpbAlmacen().getId();
						Long coArticulo = documentoMov.getClpdArticulo().getId();
						BigDecimal vaCantidad = articulo.getVaCantidad();
						
						if(mapStockAlmCat.get(coAlmacen+"-"+coArticulo) == null){
							mapStockAlmCat.put(coAlmacen+"-"+coArticulo, vaCantidad);
						}else{
							
							BigDecimal cantidadAsig = new BigDecimal(mapStockAlmCat
							.get(coAlmacen+"-"+coArticulo).toString());
							
							cantidadAsig = cantidadAsig.add(vaCantidad);
							mapStockAlmCat.put(coAlmacen+"-"+coArticulo, cantidadAsig);
						}
						
						articuloActualizado.setVaStockActual(documentoMov.getVaCantidad());
						articuloActualizado.setVaStockDisponible(documentoMov.getVaCantidad());
		
						//Lista del detalle de movimientos
						listaDetalles.add(documentoMov);	
						//Lista de transacciones
						listaTransacciones.add(transaccion);				
						//Lista de actualizacion de articulos
						listaArticulos.add(articuloActualizado);
						
					}	
				}
				
				getHibernateTemplate().saveOrUpdateAll(listaDetalles);
				getHibernateTemplate().saveOrUpdateAll(listaTransacciones);
				
				int indicador = 0;
				Set setStockAlmCat = mapStockAlmCat.keySet();
				Iterator<String> itr = setStockAlmCat.iterator();
				String[] arrayStr = new String[listaArticulos.size() + setStockAlmCat.size()];
				
				for (ClpdArticulo articulo : listaArticulos) {
					
					StringBuffer query = new StringBuffer();
					BigDecimal stockActual = articulo.getVaStockActual();
					BigDecimal stockDisponible = articulo.getVaStockDisponible();
					
					query.append(" update clpd_articulo ");
					query.append(" set ");
					query.append(" 		va_stock_actual = decode(va_stock_actual,null,"+(stockActual.negate())+",va_stock_actual - "+stockActual+"),");
					query.append(" 		va_stock_disponible = decode(va_stock_disponible,null,"+(stockDisponible.negate())+",va_stock_disponible - "+stockDisponible+"),");
					query.append(" 		co_usuario_modificador = '").append(getUsuarioLogueado().getUsername()).append("',");
					query.append(" 		da_fecha_modificacion  = sysdate");
					query.append(" where id = ").append(articulo.getId());
					
					arrayStr[indicador] = query.toString();
					indicador++;				
				}
				
				while(itr.hasNext()){
					
					String strKey     = itr.next();
			    	String[] arrayKey = strKey.split("-");
			    	Long coAlmacen  = new Long(arrayKey[0]);	    		
					Long coArticulo = new Long(arrayKey[1]);
					Long cantidadAcum = new Long(mapStockAlmCat.get(strKey).toString());
					
					//Actualizando Stock Almacen Catalogo
					StringBuffer query = new StringBuffer();
					query.append(" update clpm_stock_almacen_catalogo ");
					query.append(" set ");
					query.append(" 	va_cantidad = decode(va_cantidad,null,"+(-cantidadAcum)+",va_cantidad - "+cantidadAcum+"),");
					query.append(" 	co_usuario_modificador = '").append(getUsuarioLogueado().getUsername()).append("',");			
					query.append(" 	da_fecha_modificacion  = sysdate");
					query.append(" where 1 = 1 ");
					query.append(" and co_articulo = ").append(coArticulo);
					query.append(" and co_almacen  = ").append(coAlmacen);
					query.append(" and co_catalogo is null ");
					
					arrayStr[indicador] = query.toString();
					indicador++;
				}
				
				getHibernateTemplate().flush();
				jdbcTemplate.batchUpdate(arrayStr);
				
				for (int i = 0; i < arrayStr.length; i++) {
					System.out.println(i+"* update detalle guardarDevolucionProveedor(): "+arrayStr[i]);
				}
			}
			
			getHibernateTemplate().flush();
			mapResult.put("msg", "success");
			mapResult.put("id" , documentoMovArticulo.getId());
		
		}catch(Exception e){
			System.out.println("** Error guardarDocumentoDevolucion(): "+e.getMessage());
			getHibernateTemplate().clear();
			mapResult.put("msg", "error");
			log.info(e.getMessage());
		}
		
		return mapResult;
	}

	@SuppressWarnings("unchecked")
	public List<ClpbDocumentoMovArticulo> listaDocumentoDevolucion() {
		// Lista documento de devoluci�n al proveedor
		Criteria criteria = DetachedCriteria.forClass(ClpbDocumentoMovArticulo.class)
		.getExecutableCriteria(getSessionFactory().getCurrentSession());
		criteria.setMaxResults(CLPConstantes.MAXIMO_RESULTADO_INICIAL);
		criteria.add(Restrictions.eq("stIndicadorTipoDocumento", CLPConstantes.ST_DOCUMENTO_DEVOLUCION_PROVEEDOR));
		criteria.add(Restrictions.eq("stDocumentoMovArticulo", Boolean.TRUE));
		criteria.addOrder(Order.desc("id"));
        return (List<ClpbDocumentoMovArticulo>) criteria.list();		
	}

	@SuppressWarnings("unchecked")
	public ClpbAlmacen obtenerAlmacen(Long idAlmacen) {
		// Obtener el almacen
		Criteria criteria = DetachedCriteria.forClass(ClpbAlmacen.class).getExecutableCriteria(getSessionFactory().getCurrentSession());
		criteria.add(Restrictions.eq("id", idAlmacen));
		List<ClpbAlmacen> sacat = criteria.list();
		if(!sacat.isEmpty()){
			return sacat.get(0);
		}		
		return null;
	}
	
	@SuppressWarnings("unchecked")
	public ClpdArticulo obtenerArticulo(String coCodigoArticulo) {
		// Obtener el articulo
		Criteria criteria = DetachedCriteria.forClass(ClpdArticulo.class).getExecutableCriteria(getSessionFactory().getCurrentSession());
		criteria.add(Restrictions.eq("coCodigoArticulo", coCodigoArticulo.trim()).ignoreCase());		
	
		List<ClpdArticulo> articulos = criteria.list();
		if(!articulos.isEmpty()){
			return articulos.get(0);
		}
		return null;
	}

	@SuppressWarnings("unchecked")
	public ClpbDocumentoMovArticulo obtenerDocumentoDevolucion(Long id) {
		
		String strFechaDoc = "to_char(cast(" +
		"clpb_doc.da_fecha_documento as date),  " +
		"'"+CLPConstantes.DATE_PATTERN+"')";
		
		StringBuffer query = new StringBuffer();
		query = query.append(" SELECT clpb_doc.id  as id, ");
				query.append("        clpb_doc.de_documento  as deDocumento, ");
				query.append("        clpb_doc.de_observaciones as deObservaciones, ");
				query.append("        almacen.de_almacen as deAlmacen, ");
				query.append("        clpb_doc.de_proveedor as deProveedor ,"); 
				query.append(" "+strFechaDoc+" as deFechaDocumento ");				
				query.append("        ");
				query.append(" FROM clpb_documento_mov_articulo clpb_doc ");  
				query.append("      join clpb_almacen almacen on "); 
				query.append("        almacen.id = clpb_doc.co_almacen ");                
				query.append(" WHERE 1 = 1 "); 
				query.append("      and clpb_doc.id = " +id+ " ");
				query.append("      and clpb_doc.st_documento_mov_articulo = '" + CLPConstantes.ST_VERDADERO+ "' ");
				
				System.out.println("dev. proveedor:" + query.toString());
				List<ClpbDocumentoMovArticulo> documentos= findListOfBeans(query.toString(), null, ClpbDocumentoMovArticulo.class);				
				if(!documentos.isEmpty()){
					return documentos.get(0);
				}
				return new ClpbDocumentoMovArticulo();
	}

	@SuppressWarnings("unchecked")
	public ClpmStockAlmacenCatalogo obtenerStockAlmCata(Long idArticulo,
			Long idAlmacen, Long idCatalogo) {
		// Obtener la entidad Stock Almacen dek Catalogo
		Criteria criteria = DetachedCriteria.forClass(ClpmStockAlmacenCatalogo.class).getExecutableCriteria(getSessionFactory().getCurrentSession());
		criteria.add(Restrictions.eq("clpdArticulo.id", idArticulo));
		criteria.add(Restrictions.eq("clpbAlmacen.id",idAlmacen));
		criteria.add(Restrictions.eq("clpmCatalogo.id", idCatalogo));
		
		List<ClpmStockAlmacenCatalogo> sacat = criteria.list();
		if(!sacat.isEmpty()){
			return sacat.get(0);
		}
		return null;
	}

	@SuppressWarnings("unchecked")
	public ClpdArticulo obtenerDatosArticuloByCode(String coCodigoArticulo) {

		StringBuffer query = new StringBuffer();
		query.append(" select ");
		query.append(" art.id, ");
		query.append(" art.de_articulo as deArticulo, ");
		query.append(" art.va_stock_actual as vaStockActual, ");
		query.append(" art.co_codigo_articulo as coCodigoArticulo, ");
		query.append(" art.va_stock_disponible as vaStockDisponible ");
		
		query.append(" from clpd_articulo art ");
		query.append(" where 1 = 1 ");
		query.append(" and art.co_codigo_articulo = '").append(coCodigoArticulo).append("'");
		List<ClpdArticulo> listBean = findListOfBeans(query.toString(), null, ClpdArticulo.class);
		
		if(!listBean.isEmpty()){
			return listBean.get(0);
		}
		
		return new ClpdArticulo();
	}

}
